package com.java.springcloud.mybatisplus.conditions;

import com.baomidou.mybatisplus.core.conditions.ISqlSegment;
import com.baomidou.mybatisplus.core.conditions.SharedString;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.java.springcloud.mybatisplus.conditions.segments.TdMergeSegments;
import com.java.springcloud.mybatisplus.enums.FillType;
import com.java.springcloud.mybatisplus.enums.TdSqlKeyword;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.StringJoiner;

import static java.util.stream.Collectors.joining;

/**
 * @author Administrator
 */
public class TdQueryLambdaWrapper<T> extends LambdaQueryWrapper<T> {

    protected TdMergeSegments expression = new TdMergeSegments();
    protected SharedString sqlSelect = SharedString.emptyString();
    private static final String FIELD_ALIAS = "%s(%s) AS %s";
    private String tableSuffix = StringPool.EMPTY;
    private StringJoiner columList = new StringJoiner(StringPool.COMMA);

    public final LambdaQueryWrapper<T> max(SFunction<T, ?>... columns) {
        statistics(TdSqlKeyword.MAX, columns);
        return typedThis;
    }

    public final LambdaQueryWrapper<T> max(SFunction<T, ?> column, String alias) {
        statistics(TdSqlKeyword.MAX, column, alias);
        return typedThis;
    }

    public final LambdaQueryWrapper<T> min(SFunction<T, ?>... columns) {
        statistics(TdSqlKeyword.MIN, columns);
        return typedThis;
    }

    public final LambdaQueryWrapper<T> avg(SFunction<T, ?>... columns) {
        statistics(TdSqlKeyword.AVG, columns);
        return typedThis;
    }

    public final LambdaQueryWrapper<T> sum(SFunction<T, ?>... columns) {
        statistics(TdSqlKeyword.SUM, columns);
        return typedThis;
    }

    public final LambdaQueryWrapper<T> first(SFunction<T, ?>... columns) {
        statistics(TdSqlKeyword.FIRST, columns);
        return typedThis;
    }

    public final LambdaQueryWrapper<T> last(SFunction<T, ?>... columns) {
        statistics(TdSqlKeyword.LAST, columns);
        return typedThis;
    }

    private final LambdaQueryWrapper<T> statistics(TdSqlKeyword keyword, SFunction<T, ?>... columns) {
        if (ArrayUtils.isNotEmpty(columns)) {
            this.columList.add(columnsToString(keyword, columns));
        }
        return typedThis;
    }

    private final LambdaQueryWrapper<T> statistics(TdSqlKeyword keyword, SFunction<T, ?> column, String alias) {
        this.columList.add(columnToStringWithAlias(keyword, column, alias));
        return typedThis;
    }

    public final LambdaQueryWrapper<T> interval(Object val) {
        return window(true, TdSqlKeyword.INTERVAL, val);
    }

    public final LambdaQueryWrapper<T> sliding(Object val) {
        return window(true, TdSqlKeyword.SLIDING, val);
    }

    public final LambdaQueryWrapper<T> fill(FillType type) {
        return doIt(true, TdSqlKeyword.FILL, () -> type.getKeyword());
    }

    public final LambdaQueryWrapper<T> fill(FillType type, Object val) {
        return doIt(true, TdSqlKeyword.FILL, () -> type.getKeyword(), () -> val.toString());
    }

    private final LambdaQueryWrapper<T> window(boolean condition, TdSqlKeyword keyword, Object val) {
        return doIt(condition, keyword, () -> val.toString());
    }

    public final LambdaQueryWrapper<T> tableSuffix(String tableSuffix) {
        this.tableSuffix = tableSuffix;
        return typedThis;
    }

    @Override
    protected LambdaQueryWrapper<T> doIt(boolean condition, ISqlSegment... sqlSegments) {
        if (condition) {
            expression.add(sqlSegments);
        }
        return typedThis;
    }

    @Override
    public String getSqlSelect() {
        String superSelect = super.getSqlSelect();
        if (StringUtils.isNotBlank(superSelect) && columList.length() != 0) {
            return superSelect + StringPool.COMMA + columList;
        }
        return StringUtils.defaultString(superSelect) + columList;
    }

    private String columnsToString(TdSqlKeyword keyword, SFunction<T, ?>... columns) {
        return Arrays.stream(columns).map(i -> columnToString(keyword, i)).collect(joining(StringPool.COMMA));
    }

    private String columnToString(TdSqlKeyword keyword, SFunction<T, ?> column) {
        String fieldName = this.columnToString(column, true);
        return String.format(FIELD_ALIAS, keyword.getSqlSegment(), fieldName, fieldName);
    }

    private String columnToStringWithAlias(TdSqlKeyword keyword, SFunction<T, ?> column, String alias) {
        String fieldName = this.columnToString(column, true);
        return String.format(FIELD_ALIAS, keyword.getSqlSegment(), fieldName, alias);
    }

    @Override
    public String getSqlSegment() {
        String sqlSegment = expression.getSqlSegment();
        if (StringUtils.isNotEmpty(sqlSegment)) {
            return sqlSegment + lastSql.getStringValue();
        }
        if (StringUtils.isNotEmpty(lastSql.getStringValue())) {
            return lastSql.getStringValue();
        }
        return null;
    }

    @Override
    public MergeSegments getExpression() {
        return expression;
    }

    public String getTableSuffix() {
        return tableSuffix;
    }

}
